package net.alteiar.ui.editor;

import java.awt.Color;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.HashSet;
import java.util.Stack;

import net.alteiar.images.BasicImage;
import net.alteiar.images.IDrawable;
import net.alteiar.images.ImageFiltered;
import net.alteiar.images.filter.elements.BlockingFilter;
import net.alteiar.images.metadata.ImageInfo;
import net.alteiar.ui.ZoomablePanel;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;

public class ImageInfoEditorVision extends ZoomablePanel<IDrawable> {
	private static final long serialVersionUID = 1L;

	private final ImageInfo info;

	private static ImageFiltered buildImage(BasicImage img, ImageInfo info) {
		ImageFiltered result = new ImageFiltered(img);
		// result.addImage(new GridFilter(info, 15, Color.RED));
		// result.addImage(new GridFilter(info, 30, Color.BLACK));
		result.addImage(new BlockingFilter(info));
		return result;
	}

	public ImageInfoEditorVision(BasicImage img, ImageInfo info) {
		super(buildImage(img, info));

		this.info = info;

		this.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				setValue();
			}
		});
	}

	private static Instances buildInstances(BufferedImage img, int xBegin,
			int yBegin, int width, int height) {
		FastVector attrs = new FastVector();
		attrs.addElement(new Attribute("r"));
		attrs.addElement(new Attribute("g"));
		// attrs.addElement(new Attribute("b"));
		// attrs.addElement(new Attribute("x"));
		// attrs.addElement(new Attribute("y"));

		Instances instances = new Instances("image", attrs, 0);

		for (int x = xBegin; x < (xBegin + width); x += 2) {
			for (int y = yBegin; y < (yBegin + height); y += 2) {
				Color c = new Color(img.getRGB(x, y));

				Instance inst = buildInstance(c, x, y);
				if (inst != null) {
					instances.add(inst);
				}
			}
		}

		return instances;
	}

	private static Instance buildInstance(Color c, int x, int y) {
		return new Instance(1.0, new double[] { c.getRed(), c.getGreen() });
		// new Instance(1.0, new double[] { c.getRed(), c.getGreen(),
		// c.getBlue(), x, y });
	}

	private static void nonRecursiveFill(BufferedImage img, Point begin,
			int oldColor, ImageInfo colors, int newColor) {

		Stack<Point> pending = new Stack<Point>();
		pending.push(begin);

		HashSet<Point> visited = new HashSet<>();
		while (!pending.empty()) {
			Point p = pending.pop();
			if (!visited.contains(p)) {
				visited.add(p);

				if (isValid(img, p.x, p.y)
						&& isColor(img.getRGB(p.x, p.y), oldColor)) {

					colors.setBatchValue(p.x, p.y, newColor);

					pending.push(new Point(p.x - 1, p.y));
					pending.push(new Point(p.x + 1, p.y));
					pending.push(new Point(p.x, p.y - 1));
					pending.push(new Point(p.x, p.y + 1));
				}
			}
		}

		colors.endBatchModification();
	}

	private static boolean isValid(BufferedImage img, int x, int y) {
		return x >= 0 && x < img.getWidth() && y >= 0 && y < img.getHeight();
	}

	public static boolean isColor(int color, int target) {
		Color c = new Color(color);
		Color t = new Color(target);

		int dist = Math.abs(t.getRed() - c.getRed())
				+ Math.abs(t.getGreen() - c.getGreen())
				+ Math.abs(t.getBlue() - c.getBlue());

		return dist < 76;
	}

	public void setValue() {
		Point imgPos = this.panelToImage(getMousePosition());
		// int beginX = (imgPos.x / 15) * 15;
		// int beginY = (imgPos.y / 15) * 15;

		BufferedImage img = this.info.getImage().getImage();
		int c = img.getRGB(imgPos.x, imgPos.y);

		this.info.fill(Integer.MAX_VALUE);
		nonRecursiveFill(img, imgPos, c, this.info, 1);

		this.info.endBatchModification();
		/*
		System.out.println("build instances");
		Instances data = buildInstances(img, beginX, beginY, 15, 15);

		System.out.println("clustering");
		SimpleKMeans clusterer = new SimpleKMeans();
		try {
			clusterer.setNumClusters(2);
			clusterer.setDistanceFunction(new EuclideanDistance());
			clusterer.setMaxIterations(1000);
			clusterer.buildClusterer(data);
		} catch (Exception e) {
			e.printStackTrace();
		}

		ClusterEvaluation eval = new ClusterEvaluation();
		eval.setClusterer(clusterer);
		try {
			eval.evaluateClusterer(data);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		System.out.println("evaluation: " + eval.clusterResultsToString());

		for (int x = beginX; x < (beginX + 15); ++x) {
			for (int y = beginY; y < (beginY + 15); ++y) {
				try {

					int c = clusterer.clusterInstance(buildInstance(new Color(
							img.getRGB(x, y)), x, y));
					if (c == 1) {
						this.info.setBatchValueAt(x, y, Integer.MAX_VALUE);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

		this.info.endBatchModification();
		*/
	}
}
